package com.sws.web.controller.student_attendance.device;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.sws.device.config.WebSocketConfig;
import com.sws.device.constant.ErrorCode;
import com.sws.device.domain.DevDeviceDTO;
import com.sws.device.domain.model.*;
import com.sws.device.service.DevDeviceWebSocketService;
import com.sws.device.util.MessageUtil;
import com.sws.device.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.net.SocketException;
import java.nio.channels.ClosedChannelException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 设备WebSocket端点
 * 处理设备连接和通信
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws/device/{deviceId}", configurator = WebSocketConfig.CustomConfigurator.class)
public class DeviceWebSocketEndpoint {

    // 在线设备会话，使用ConcurrentHashMap保证线程安全
    private static final Map<String, Session> ONLINE_DEVICES = new ConcurrentHashMap<>();
    
    // 设备ID和设备SN的映射，用于跟踪哪个设备ID对应哪个设备SN
    private static final Map<String, String> DEVICE_ID_SN_MAP = new ConcurrentHashMap<>();
    
    // 设备服务
    private static DevDeviceWebSocketService deviceService;
    
    // 连接计数器
    private static final AtomicInteger connectionCount = new AtomicInteger(0);
    
    // 最大连接数
    private static final int MAX_CONNECTIONS = 5000;
    
    // 会话配置 - 不能使用@Value注入静态变量，改用非静态变量和静态方法
    private static long maxIdleTimeout = 3600000; // 1小时
    private static int maxTextMessageBufferSize = 131072; // 128KB
    private static int maxBinaryMessageBufferSize = 131072; // 128KB
    
    @Value("${server.websocket.max-idle-timeout:3600000}")
    public void setMaxIdleTimeout(long timeout) {
        DeviceWebSocketEndpoint.maxIdleTimeout = timeout;
    }
    
    @Value("${spring.websocket.max-text-message-buffer-size:131072}")
    public void setMaxTextMessageBufferSize(int size) {
        DeviceWebSocketEndpoint.maxTextMessageBufferSize = size;
    }
    
    @Value("${spring.websocket.max-binary-message-buffer-size:131072}")
    public void setMaxBinaryMessageBufferSize(int size) {
        DeviceWebSocketEndpoint.maxBinaryMessageBufferSize = size;
    }
    
    @Autowired
    public void setDeviceService(DevDeviceWebSocketService deviceService) {
        DeviceWebSocketEndpoint.deviceService = deviceService;
    }
    
    /**
     * 连接建立时调用
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("deviceId") String deviceId) {
        log.info("新的WebSocket连接请求: {}, 设备ID: {}", session.getId(), deviceId);
        
        // 连接数限制
        int currentConnections = connectionCount.incrementAndGet();
        if (currentConnections > MAX_CONNECTIONS) {
            log.warn("连接数超过限制 ({}), 拒绝设备ID: {} 的连接", MAX_CONNECTIONS, deviceId);
            connectionCount.decrementAndGet();
            try {
                CloseReason reason = new CloseReason(CloseReason.CloseCodes.TRY_AGAIN_LATER, "连接数超过限制");
                session.close(reason);
            } catch (IOException e) {
                log.error("关闭超限连接时发生错误: {}", e.getMessage(), e);
            }
            return;
        }
        
        try {
            // 设置会话超时时间
            session.setMaxIdleTimeout(maxIdleTimeout);
            
            // 设置更大的消息缓冲区
            session.setMaxTextMessageBufferSize(maxTextMessageBufferSize);
            session.setMaxBinaryMessageBufferSize(maxBinaryMessageBufferSize);
            
            // 设置错误处理选项
            session.getUserProperties().put("org.apache.tomcat.websocket.closeReason", CloseReason.CloseCodes.NORMAL_CLOSURE);
            
            // 开启自动关闭超时连接
            session.getUserProperties().put("org.apache.tomcat.websocket.autoClose", true);
            
            // 记录设备ID，但不保存到ONLINE_DEVICES，等待连接认证后再保存
            log.info("设备ID: {} 的WebSocket会话参数已设置，等待认证，当前连接数: {}", deviceId, currentConnections);
        } catch (Exception e) {
            log.error("设置会话参数时发生错误: {}", e.getMessage(), e);
            connectionCount.decrementAndGet();
            try {
                session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, "配置错误"));
            } catch (IOException ex) {
                log.error("关闭配置错误的连接时发生异常: {}", ex.getMessage(), ex);
            }
        }
    }

    /**
     * 收到客户端消息时调用
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("deviceId") String deviceId) {
        log.info("收到来自设备[{}]的消息: {}", deviceId, message);
        
        try {
            // 验证消息大小
            if (message.length() > maxTextMessageBufferSize) {
                log.warn("设备 {} 发送的消息过大: {} 字节，超过限制: {} 字节", deviceId, message.length(), maxTextMessageBufferSize);
                sendMessage(session, MessageUtil.createErrorResponse("unknown", null, ErrorCode.BAD_REQUEST, "消息过大"));
                return;
            }
            
            // 解析消息
            WebSocketMessage wsMessage = JSON.parseObject(message, WebSocketMessage.class);
            String msgid = wsMessage.getMsgid();
            WebSocketMessage.MessageData data = wsMessage.getData();
            
            if (data == null || data.getUri() == null) {
                sendMessage(session, MessageUtil.createErrorResponse(msgid, null, ErrorCode.BAD_REQUEST, "无效的请求格式"));
                return;
            }
            
            // 根据URI处理不同的请求
            String uri = data.getUri();
            switch (uri) {
                case "/connect":
                    handleConnect(session, wsMessage, deviceId);
                    break;
                case "/token/update":
                    handleTokenUpdate(session, wsMessage, deviceId);
                    break;
                case "/heartbeat":
                    handleHeartbeat(session, wsMessage, deviceId);
                    break;
                default:
                    sendMessage(session, MessageUtil.createErrorResponse(msgid, uri, ErrorCode.NOT_FOUND, "未知的操作URI"));
                    break;
            }
        } catch (Exception e) {
            log.error("处理消息时发生错误: {}", e.getMessage(), e);
            try {
                sendMessage(session, MessageUtil.createErrorResponse("unknown", null, ErrorCode.SERVER_ERROR, "服务器内部错误"));
            } catch (Exception ex) {
                log.error("发送错误消息时发生异常: {}", ex.getMessage(), ex);
            }
        }
    }

    /**
     * 处理设备连接请求
     */
    private void handleConnect(Session session, WebSocketMessage wsMessage, String deviceId) throws IOException {
        String msgid = wsMessage.getMsgid();
        JSONObject paramObj = (JSONObject) wsMessage.getData().getParam();
        
        try {
            // 检查会话是否仍然打开
            if (session == null || !session.isOpen()) {
                log.warn("设备 ID: {} 的会话已关闭或无效，无法处理连接请求", deviceId);
                return;
            }
            
            // 解析连接参数
            ConnectParam connectParam = paramObj.toJavaObject(ConnectParam.class);
            
            if (connectParam.getSn() == null || connectParam.getTs() == null) {
                sendMessage(session, MessageUtil.createErrorResponse(msgid, "/connect", ErrorCode.BAD_REQUEST, "缺少必要参数"));
                return;
            }
            
            // 设备序列号
            String deviceSn = connectParam.getSn();
            
            // 如果接收到的时间戳，确保使用北京时区处理
            if (connectParam.getTs() != null) {
                // 时间戳已经在参数中，不需要额外转换
                // 在后续数据库操作时会用到这个时间戳
            }
            
            // 检查设备是否已连接，如果已连接，先清理之前的连接
            if (ONLINE_DEVICES.containsKey(deviceSn)) {
                Session oldSession = ONLINE_DEVICES.get(deviceSn);
                if (oldSession != null && oldSession.isOpen() && !oldSession.equals(session)) {
                    try {
                        log.warn("设备 {} 有多个活跃连接，关闭旧连接", deviceSn);
                        oldSession.close();
                    } catch (Exception e) {
                        log.error("关闭设备 {} 的旧连接时发生错误: {}", deviceSn, e.getMessage());
                    }
                }
                // 清理旧的映射关系
                for (Map.Entry<String, String> entry : DEVICE_ID_SN_MAP.entrySet()) {
                    if (deviceSn.equals(entry.getValue()) && !deviceId.equals(entry.getKey())) {
                        DEVICE_ID_SN_MAP.remove(entry.getKey());
                        break;
                    }
                }
            }
            
            // 生成token
            String token = TokenUtil.generateToken(deviceSn);
            
            // 保存设备会话和设备ID与SN的映射
            ONLINE_DEVICES.put(deviceSn, session);
            DEVICE_ID_SN_MAP.put(deviceId, deviceSn);
            
            // 设置响应参数
            int expire = 3600; // token有效期1小时
            int interval = 30; // 心跳间隔30秒
            
            // 保存或更新设备信息到数据库
            String ip = connectParam.getIp();
            Integer ts = connectParam.getTs().intValue(); // 确保类型是Integer
            DevDeviceDTO device = null;
            
            try {
                if (deviceService != null) {
                    device = deviceService.handleDeviceConnect(deviceSn, ip, ts, token, expire, interval);
                    log.info("设备信息已保存到数据库: {}, 设备ID: {}", device.getSn(), deviceId);
                } else {
                    log.warn("设备服务未注入，无法保存设备信息到数据库");
                }
            } catch (Exception e) {
                log.error("保存设备信息到数据库时发生错误: {}", e.getMessage(), e);
                // 继续处理，不影响连接响应
            }
            
            // 构建响应
            ConnectResult result = new ConnectResult();
            result.setToken(token);
            
            // 如果成功从数据库获取了设备信息，使用数据库中的过期时间和心跳间隔
            if (device != null) {
                // 计算剩余有效时间（秒）
                if (device.getTokenExpireTime() != null) {
                    long currentTimeMillis = System.currentTimeMillis();
                    long expireTimeMillis = device.getTokenExpireTime().getTime();
                    long remainingMillis = expireTimeMillis - currentTimeMillis;
                    
                    // 转换为秒并确保不小于0
                    int remainingSeconds = (int) Math.max(0, remainingMillis / 1000);
                    result.setExpire(remainingSeconds);
                } else {
                    result.setExpire(expire);
                }
                
                result.setInterval(device.getHeartbeatInterval() != null ? device.getHeartbeatInterval() : interval);
            } else {
                // 否则使用默认值
                result.setExpire(expire);
                result.setInterval(interval);
            }
            
            // 再次检查会话是否仍然打开
            if (session == null || !session.isOpen()) {
                log.warn("设备 {} (ID: {}) 的会话在处理过程中已关闭，无法发送响应", deviceSn, deviceId);
                cleanupSession(deviceSn, deviceId);
                return;
            }
            
            WebSocketMessage response = MessageUtil.createSuccessResponse(msgid, "/connect", result);
            try {
                sendMessage(session, response);
                log.info("设备 {} (ID: {}) 已连接，分配token: {}, 过期时间: {}秒, 心跳间隔: {}秒", 
                        deviceSn, deviceId, token, result.getExpire(), result.getInterval());
            } catch (IOException e) {
                log.error("发送连接响应时发生错误: {}", e.getMessage(), e);
                if (e instanceof SocketException) {
                    log.warn("设备 {} (ID: {}) 可能已断开连接: {}", deviceSn, deviceId, e.getMessage());
                    // 清理会话
                    cleanupSession(deviceSn, deviceId);
                }
                throw e;
            }
        } catch (Exception e) {
            log.error("处理设备 {} 连接请求时发生未处理的异常: {}", deviceId, e.getMessage(), e);
            if (session != null && session.isOpen()) {
                sendMessage(session, MessageUtil.createErrorResponse(msgid, "/connect", ErrorCode.SERVER_ERROR, "服务器内部错误"));
            }
        }
    }
    
    /**
     * 处理Token更新请求
     */
    private void handleTokenUpdate(Session session, WebSocketMessage wsMessage, String deviceId) throws IOException {
        String msgid = wsMessage.getMsgid();
        String token = wsMessage.getToken();
        JSONObject paramObj = (JSONObject) wsMessage.getData().getParam();
        
        // 解析Token更新参数
        TokenUpdateParam tokenUpdateParam = paramObj.toJavaObject(TokenUpdateParam.class);
        
        if (tokenUpdateParam.getSn() == null) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/token/update", ErrorCode.BAD_REQUEST, "缺少设备序列号"));
            return;
        }
        
        String deviceSn = tokenUpdateParam.getSn();
        
        // 验证设备ID与SN是否匹配
        if (!validateDeviceIdSn(deviceId, deviceSn)) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/token/update", ErrorCode.UNAUTHORIZED, "设备ID与SN不匹配"));
            return;
        }
        
        // 验证Token
        if (!TokenUtil.validateToken(token, deviceSn)) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/token/update", ErrorCode.UNAUTHORIZED, "无效的Token"));
            return;
        }
        
        // 更新Token
        String updatedToken = TokenUtil.updateToken(deviceSn);
        
        // 设置响应参数
        int expire = 3600; // 重新设置为1小时
        DevDeviceDTO device = null;
        
        // 更新设备Token信息到数据库
        try {
            if (deviceService != null) {
                device = deviceService.updateDeviceToken(deviceSn, updatedToken, expire);
                if (device != null) {
                    log.info("设备Token信息已更新到数据库: {}, 设备ID: {}", device.getSn(), deviceId);
                    
                    // 计算剩余有效时间（秒）
                    if (device.getTokenExpireTime() != null) {
                        long currentTimeMillis = System.currentTimeMillis();
                        long expireTimeMillis = device.getTokenExpireTime().getTime();
                        long remainingMillis = expireTimeMillis - currentTimeMillis;
                        
                        // 转换为秒并确保不小于0
                        expire = (int) Math.max(0, remainingMillis / 1000);
                    }
                } else {
                    log.warn("设备不存在，无法更新Token信息到数据库: {}, 设备ID: {}", deviceSn, deviceId);
                }
            } else {
                log.warn("设备服务未注入，无法更新设备Token信息到数据库");
            }
        } catch (Exception e) {
            log.error("更新设备Token信息到数据库时发生错误: {}", e.getMessage(), e);
            // 继续处理，不影响响应
        }
        
        // 构建响应
        TokenUpdateResult result = new TokenUpdateResult();
        result.setToken(updatedToken);
        result.setExpire(expire);
        
        WebSocketMessage response = MessageUtil.createSuccessResponse(msgid, "/token/update", result);
        sendMessage(session, response);
        
        log.info("设备 {} (ID: {}) 更新Token成功，新token: {}, 过期时间: {}秒", deviceSn, deviceId, updatedToken, expire);
    }
    
    /**
     * 处理心跳请求
     */
    private void handleHeartbeat(Session session, WebSocketMessage wsMessage, String deviceId) throws IOException {
        log.debug("已收到设备[{}]传来的心跳请求：{}", deviceId, wsMessage);
        String msgid = wsMessage.getMsgid();
        String token = wsMessage.getToken();
        JSONObject paramObj = (JSONObject) wsMessage.getData().getParam();
        
        // 解析心跳参数
        HeartbeatParam heartbeatParam = paramObj.toJavaObject(HeartbeatParam.class);
        
        if (heartbeatParam.getSn() == null) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/heartbeat", ErrorCode.BAD_REQUEST, "缺少设备序列号"));
            return;
        }
        
        String deviceSn = heartbeatParam.getSn();
        
        // 验证设备ID与SN是否匹配
        if (!validateDeviceIdSn(deviceId, deviceSn)) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/heartbeat", ErrorCode.UNAUTHORIZED, "设备ID与SN不匹配"));
            return;
        }
        
        // 验证Token
        if (!TokenUtil.validateToken(token, deviceSn)) {
            sendMessage(session, MessageUtil.createErrorResponse(msgid, "/heartbeat", ErrorCode.UNAUTHORIZED, "无效的Token"));
            return;
        }
        
        // 获取Token剩余有效时间，使用数据库中的信息
        int remainExpire = TokenUtil.getTokenExpire(token, deviceSn);
        
        // 更新设备心跳信息到数据库
        String deviceIp = heartbeatParam.getIp();
        DevDeviceDTO device = null;
        
        try {
            if (deviceService != null) {
                device = deviceService.updateDeviceHeartbeat(deviceSn, deviceIp);
                if (device != null) {
                    log.info("设备[{}]心跳信息已更新到数据库: {}  token有效剩余时间： {}", deviceId, device.getSn(), remainExpire);
                    
                    // 如果数据库更新成功，重新计算剩余时间
                    if (device.getTokenExpireTime() != null) {
                        long currentTimeMillis = System.currentTimeMillis();
                        long expireTimeMillis = device.getTokenExpireTime().getTime();
                        long remainingMillis = expireTimeMillis - currentTimeMillis;
                        
                        // 转换为秒并确保不小于0
                        remainExpire = (int) Math.max(0, remainingMillis / 1000);
                        log.debug("设备 {} (ID: {}) 的token过期时间: {}, 当前时间: {}, 剩余时间: {}秒", 
                                deviceSn, deviceId, new Date(expireTimeMillis), new Date(currentTimeMillis), remainExpire);
                    }
                    
                } else {
                    log.warn("设备不存在，无法更新心跳信息到数据库: {}, 设备ID: {}", deviceSn, deviceId);
                }
            } else {
                log.warn("设备服务未注入，无法更新设备心跳信息到数据库");
            }
        } catch (Exception e) {
            log.error("更新设备心跳信息到数据库时发生错误: {}", e.getMessage(), e);
            // 继续处理，不影响响应
        }
        
        // 构建响应
        HeartbeatResult result = new HeartbeatResult();
        result.setExpire(remainExpire);
        
        WebSocketMessage response = MessageUtil.createSuccessResponse(msgid, "/heartbeat", result);
        
        try {
            sendMessage(session, response);
            
            if (deviceIp != null) {
                log.info("设备 {} (ID: {}) 心跳成功，IP: {}，剩余时间: {}秒", deviceSn, deviceId, deviceIp, remainExpire);
            } else {
                log.info("设备 {} (ID: {}) 心跳成功，剩余时间: {}秒", deviceSn, deviceId, remainExpire);
            }
            
            // 检查剩余时间是否在特定范围内，如果是，记录详细日志
            if (remainExpire >= 2540 && remainExpire <= 2580) {
                log.warn("设备 {} (ID: {}) 的token剩余时间为 {}秒，处于可能导致连接关闭的风险区间", deviceSn, deviceId, remainExpire);
            }
        } catch (IOException e) {
            log.error("发送心跳响应时发生错误: {}", e.getMessage(), e);
            if (e instanceof SocketException) {
                log.warn("设备 {} (ID: {}) 可能已断开连接: {}", deviceSn, deviceId, e.getMessage());
                // 清理会话
                cleanupSession(deviceSn, deviceId);
            }
            throw e;
        }
    }

    /**
     * 连接关闭时调用
     */
    @OnClose
    public void onClose(Session session, @PathParam("deviceId") String deviceId) {
        log.info("WebSocket连接已关闭: {}, 设备ID: {}", session.getId(), deviceId);
        
        // 减少连接计数
        connectionCount.decrementAndGet();
        
        // 查找对应的设备SN
        String deviceSn = DEVICE_ID_SN_MAP.get(deviceId);
        if (deviceSn != null) {
            cleanupSession(deviceSn, deviceId);
            log.info("设备 {} (ID: {}) 已断开连接", deviceSn, deviceId);
        } else {
            // 如果找不到对应的设备SN，尝试遍历查找
            for (Map.Entry<String, Session> entry : ONLINE_DEVICES.entrySet()) {
                if (entry.getValue().equals(session)) {
                    deviceSn = entry.getKey();
                    cleanupSession(deviceSn, deviceId);
                    log.info("设备 {} (ID: {}) 已断开连接", deviceSn, deviceId);
                    break;
                }
            }
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error, @PathParam("deviceId") String deviceId) {
        // 特殊处理应用关闭时的常见异常
        if (error instanceof SocketException || error instanceof ClosedChannelException || 
            "Connection reset by peer".equals(error.getMessage()) ||
            (error instanceof IOException && error.getCause() instanceof ClosedChannelException)) {
            log.debug("WebSocket连接已被关闭，这可能是应用关闭或重启导致的, 设备ID: {}", deviceId);
        } else {
            log.error("WebSocket发生错误: {}, 设备ID: {}", error.getMessage(), deviceId, error);
        }
        
        // 查找对应的设备SN
        String deviceSn = DEVICE_ID_SN_MAP.get(deviceId);
        if (deviceSn != null) {
            cleanupSession(deviceSn, deviceId);
            log.debug("已清理设备 {} (ID: {}) 的会话资源", deviceSn, deviceId);
        } else {
            // 如果找不到对应的设备SN，尝试遍历查找
            for (Map.Entry<String, Session> entry : ONLINE_DEVICES.entrySet()) {
                if (entry.getValue().equals(session)) {
                    deviceSn = entry.getKey();
                    cleanupSession(deviceSn, deviceId);
                    log.debug("已清理设备 {} (ID: {}) 的会话资源", deviceSn, deviceId);
                    break;
                }
            }
        }
        
        // 确保连接计数正确
        connectionCount.decrementAndGet();
    }
    
    /**
     * 清理设备会话资源
     */
    private void cleanupSession(String deviceSn, String deviceId) {
        try {
            // 获取会话并尝试关闭
            Session session = ONLINE_DEVICES.get(deviceSn);
            if (session != null && session.isOpen()) {
                try {
                    session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "会话清理"));
                } catch (IOException e) {
                    // 在应用关闭过程中，这里可能会抛出异常，但这是正常的，只需记录调试信息
                    log.debug("关闭设备 {} 会话时发生可忽略的错误: {}", deviceSn, e.getMessage());
                }
            }
            
            ONLINE_DEVICES.remove(deviceSn);
            DEVICE_ID_SN_MAP.remove(deviceId);
            TokenUtil.removeToken(deviceSn);
            
            // 更新设备在数据库中的状态
            // TODO: 需要在DevDeviceWebSocketService中实现updateDeviceStatus方法
            /*
            try {
                if (deviceService != null) {
                    deviceService.updateDeviceStatus(deviceSn, false);
                    log.info("设备 {} 的在线状态已更新为离线", deviceSn);
                }
            } catch (Exception e) {
                log.error("更新设备 {} 状态时发生错误: {}", deviceSn, e.getMessage(), e);
            }
            */
        } catch (Exception e) {
            log.debug("清理设备 {} 会话资源时发生可忽略的异常: {}", deviceSn, e.getMessage());
        }
    }
    
    /**
     * 验证设备ID与SN是否匹配
     */
    private boolean validateDeviceIdSn(String deviceId, String deviceSn) {
        if (deviceId == null || deviceSn == null) {
            log.warn("设备ID或SN为空，无法验证");
            return false;
        }
        
        String mappedSn = DEVICE_ID_SN_MAP.get(deviceId);
        return deviceSn.equals(mappedSn);
    }
    
    /**
     * 获取当前活跃连接数
     */
    public static int getActiveConnectionCount() {
        return connectionCount.get();
    }
    
    /**
     * 获取在线设备数量
     */
    public static int getOnlineDeviceCount() {
        return ONLINE_DEVICES.size();
    }
    
    /**
     * 强制断开指定设备的连接
     * 
     * @param deviceSn 设备序列号
     * @return 是否成功断开
     */
    public static boolean forceDisconnect(String deviceSn) {
        if (deviceSn == null) {
            return false;
        }
        
        Session session = ONLINE_DEVICES.get(deviceSn);
        if (session != null && session.isOpen()) {
            try {
                // 查找设备ID
                String deviceId = null;
                for (Map.Entry<String, String> entry : DEVICE_ID_SN_MAP.entrySet()) {
                    if (deviceSn.equals(entry.getValue())) {
                        deviceId = entry.getKey();
                        break;
                    }
                }
                
                // 关闭会话
                session.close(new CloseReason(CloseReason.CloseCodes.SERVICE_RESTART, "强制断开"));
                
                // 清理会话资源
                if (deviceId != null) {
                    ONLINE_DEVICES.remove(deviceSn);
                    DEVICE_ID_SN_MAP.remove(deviceId);
                    TokenUtil.removeToken(deviceSn);
                    log.info("已强制断开设备 {} (ID: {}) 的连接", deviceSn, deviceId);
                }
                
                return true;
            } catch (IOException e) {
                log.error("强制断开设备 {} 连接时发生错误: {}", deviceSn, e.getMessage(), e);
            }
        } else {
            log.warn("设备 {} 不在线，无法断开连接", deviceSn);
        }
        
        return false;
    }
    
    /**
     * 检查设备是否在线
     * 
     * @param deviceSn 设备序列号
     * @return 是否在线
     */
    public static boolean isDeviceOnline(String deviceSn) {
        if (deviceSn == null) {
            return false;
        }
        
        Session session = ONLINE_DEVICES.get(deviceSn);
        return session != null && session.isOpen();
    }
    
    /**
     * 发送消息
     */
    private void sendMessage(Session session, Object message) throws IOException {
        if (session == null || !session.isOpen()) {
            log.warn("尝试向已关闭或无效的会话发送消息");
            return;
        }
        
        try {
            String jsonMessage = JSON.toJSONString(message);
            // 检查消息大小，确保不超过WebSocket消息缓冲区大小
            if (jsonMessage.length() > maxTextMessageBufferSize - 1024) { // 略小于配置的限制，留一些余量
                log.warn("消息过大，长度为 {} 字节，接近缓冲区大小限制", jsonMessage.length());
            }
            
            // 添加异步发送逻辑，避免阻塞
            session.getAsyncRemote().sendText(jsonMessage);
        } catch (Exception e) {
            log.error("发送消息时发生错误: {}", e.getMessage(), e);
            if (e instanceof SocketException) {
                throw new IOException(e);
            }
        }
    }
} 